package cn.wizzer.app.crown.modules.services.impl.pl;

import cn.wizzer.framework.util.DateUtil;
import cn.wizzer.app.crown.modules.models.CrownBet;
import cn.wizzer.app.crown.modules.models.CrownMatch;
import cn.wizzer.app.crown.modules.models.constant.CrownConstant;
import cn.wizzer.app.crown.modules.models.constant.CrownPattern;
import cn.wizzer.app.crown.modules.models.enums.BetsEnum;
import cn.wizzer.app.crown.modules.services.CrownBetService;
import cn.wizzer.app.crown.modules.services.CrownMatchService;
import cn.wizzer.app.crown.modules.services.pl.PdHalfResolverService;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.util.Result;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONArray;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;

/**
 * 半场波胆玩法爬取
 */
@IocBean(args = {"refer:dao"})
@Service(interfaceClass = PdHalfResolverService.class)
public class PdHalfResolverServiceImpl extends BaseServiceImpl<CrownMatch> implements PdHalfResolverService {

    public PdHalfResolverServiceImpl(Dao dao) {
        super(dao);
    }

    private static final Log log = Logs.get();

    @Inject
    private RedisService redisService;
    @Inject
    private CrownMatchService matchService;
    @Inject
    private CrownBetService betService;
    @Reference
    @Inject
    private SysParamService sysParamService;

    public SysParamService getSysParamService() {
        return sysParamService;
    }

    /**
     * 投资内容和对应的赔率index
     */
    private Map<String, Integer> betMap = Result.createHashMap(
            "1-0", 8, "2-0", 9, "2-1", 10, "3-0", 11, "3-1", 12, "3-2", 13, "0-0", 18, "1-1", 19, "2-2", 20,
            "3-3", 21, "other", 23, "0-1", 24, "0-2", 25, "1-2", 26, "0-3", 27, "1-3", 28, "2-3", 29
    );


    public void doBiz(List<JSONArray> list, String date, String dateType) {
        log.info("pdh receive" + list);
        for (JSONArray gm : list) {
            String leagueName = gm.getString(2);
            if ("Fantasy Matches".equals(leagueName)) {
                log.info("过滤掉Fantasy Matches.mid:" + gm.getString(0));
                continue;
            }
            CrownMatch match = new CrownMatch();
            // 赛事id
            match.setMid(gm.getString(0));
            // 开赛时间
            String[] dateTime = gm.getString(1).toLowerCase().split("<br>");
            int dateTimeLength = dateTime.length;
            match.setStart(dateTimeLength == 3 ? dateTime[2] : "");
            if (CrownConstant.FUTURE.equals(dateType)) {
                match.setDateTime(DateUtil.parseDate(Calendar.getInstance().getWeekYear() + "-" + dateTime[0] + " " + (dateTimeLength >= 2 ? dateTime[1] + "m" : ""), DateUtil.DATE_FORMAT_PATTERN.Y_M_D_H_M_A.PATTERN));
            } else {
                match.setDateTime(DateUtil.parseDate(date + " " + (dateTimeLength >= 2 ? dateTime[1] + "m" : ""), DateUtil.DATE_FORMAT_PATTERN.Y_M_D_H_M_A.PATTERN));
            }
            // 皇冠时间有错误，没有处理美国时间夏令时冬令时。所以自己要处理一下
            this.handleDaylightTime(match);
            // 赛事阶段
            match.setStage(dateType);
            // 联赛名
            match.setLeague(leagueName);
            // 主队名(去掉‘[Mid]’)
            String home = gm.getString(5);
            home = CrownPattern.HTML_PATTERN.matcher(home).replaceAll("");
            //中场判断
            if (home.contains("[Mid]")) {
                home = home.replace("[Mid]", "").trim();
                match.setHaveHomeCourt(false);
            } else {
                match.setHaveHomeCourt(true);
            }
            match.setHome(home);
            // 是否有滚球
            if (Strings.isNotBlank(match.getStart()) && match.getStart().contains("running ball")) {
                match.setHaveRoll(true);
            } else {
                match.setHaveRoll(false);
            }
            // 客队名(要去掉HTML标签)
            String custom = gm.getString(6);
            custom = CrownPattern.HTML_PATTERN.matcher(custom).replaceAll("");
            match.setCustom(custom);
            // 处理赛事和投资数据
            this.handleMatchAndBets(gm, match);
        }
    }

    /**
     * 赛事、投资数据如果已入库则update，为入库则insert
     *
     * @param gm
     * @param match
     */
    private synchronized void handleMatchAndBets(JSONArray gm, CrownMatch match) {
        CrownMatch old = matchService.queryByTeamInfo(match.getLeague(), match.getHome(), match.getCustom(), match.getDateTime());
        if (old != null) {
            if (CrownConstant.OTHER.equals(old.getStage()) || CrownConstant.FINISHED.equals(old.getStage())) {
                log.info("赛事mid:" + match.getMid() + ",已被手动设置为结束状态，不再更新。任务:半场波胆");
            } else {
                log.info("update赛事,主:" + match.getHome() + ".客:" + match.getCustom() + ".联赛:" + match.getLeague()
                        + ".时间:" + match.getDateTime() + ".mid:" + match.getMid() + ".任务:半场波胆");
                match.setId(old.getId());
                match.setOpAt(Times.getTS());
                match.setProtect(old.getProtect());
                matchService.update(match);
                this.updateBets(gm, match.getId());
            }
        }
        // 插入
        else {
            log.info("首次insert赛事,主:" + match.getHome() + ".客:" + match.getCustom() + ".联赛:" + match.getLeague()
                    + ".时间:" + match.getDateTime() + ".mid:" + match.getMid() + ".任务:半场波胆");
            matchService.insert(match);
            log.info("赛事不存在，hpd初次insert crown_bet。赛事id：" + match.getId() + "。JSONArray：" + gm);
            this.insertBets(gm, match.getId());
        }
    }

    /**
     * 处理美东时间夏令时
     *
     * @param match
     */
    private void handleDaylightTime(CrownMatch match) {
        Calendar cal = Calendar.getInstance();
        Date oldTime = match.getDateTime();
        cal.setTime(oldTime);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int min = cal.get(Calendar.MINUTE);
        int sec = cal.get(Calendar.SECOND);
        ZonedDateTime now = ZonedDateTime.of(year, month, day, hour, min, sec, 0, ZoneId.of("America/New_York"));
        boolean isDayLight = now.getZone().getRules().isDaylightSavings(now.toInstant());
        // 如果是冬令时时间则date要减一小时
        if (!isDayLight) {
            cal.add(Calendar.HOUR, -1);
            match.setDateTime(cal.getTime());
            log.info("半场波胆，美国冬令时，赛事时间减一小时。赛事mid:" + match.getMid() + "。原赛事时间:" + oldTime
                    + "。修正后的赛事时间:" + match.getDateTime());
        }
    }

    @Aop(TransAop.REPEATABLE_READ)
    private void updateBets(JSONArray gm, String matchId) {
        int count = betService.count(Cnd.where("matchId", "=", matchId)
                .and("type", "=", BetsEnum.HALF_PD));
        // 更新
        if (count > 0) {
            CrownBet bet = new CrownBet();
            bet.setType(BetsEnum.HALF_PD);
            for (Map.Entry<String, Integer> entry : betMap.entrySet()) {
                String key = entry.getKey();
                Integer value = entry.getValue();
                if (key.contains("3") || key.contains("other")) {
                    continue;
                }
                // 转换赔率
                bet.setOdds(gm.getBigDecimal(value));
                matchService.handleRate(bet);
                // 只更新rateUpdateFlag为true的rate字段(赔率)
                Chain chain = Chain.make("odds", bet.getOdds()).add("rate", bet.getRate());
                Cnd cnd = Cnd.where("matchId", "=", matchId)
                        .and("type", "=", BetsEnum.HALF_PD)
                        .and("betContent", "=", key)
                        .and("rateUpdateFlag", "=", 1);
                int i = betService.update(chain, cnd);
                if (i == 0) {
                    CrownBet betI = new CrownBet();
                    betI.setMatchId(matchId);
                    betI.setType(BetsEnum.HALF_PD);
                    betI.setRecruitAmount(sysParamService.fetch().getRecruitAmount());
                    // 波胆比分
                    betI.setBetContent(key);
                    // 处理赔率
                    betI.setOdds(gm.getBigDecimal(value));
                    matchService.handleRate(betI);
                    betService.insertOrUpdate(betI);
                }
            }
            betService.clearCache(matchId, bet.getType());
        }
        // 插入
        else {
            log.info("赛事已存在，pd初次insert crown_bet。赛事id：" + matchId + "。JSONArray：" + gm);
            this.insertBets(gm, matchId);
        }
    }

    private void insertBets(JSONArray gm, String matchId) {
        List<CrownBet> bets = new ArrayList<>();
        // 获取‘招募金额’
        BigDecimal recruitAmount = sysParamService.fetch().getRecruitAmount();
        // 获取投资内容以及赔率
        for (Map.Entry<String, Integer> entry : betMap.entrySet()) {
            String key = entry.getKey();
            if (key.contains("3") || key.contains("other")) {
                continue;
            }
            Integer value = entry.getValue();
            CrownBet bet = new CrownBet();
            bet.setMatchId(matchId);
            bet.setType(BetsEnum.HALF_PD);
            bet.setRecruitAmount(recruitAmount);
            // 记录波胆比分
            bet.setBetContent(key);
            // 处理赔率
            bet.setOdds(gm.getBigDecimal(value));
            matchService.handleRate(bet);
            // 加入集合
            bets.add(bet);
        }
        betService.fastInsert(bets);
        betService.clearCache(matchId, BetsEnum.HALF_PD);
    }

}
